/*
 * Created on Apr 13, 2004
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package abdn.graph.ontobrowser;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

import javax.swing.JScrollBar;

import com.touchgraph.graphlayout.LocalityUtils;
import com.touchgraph.graphlayout.Node;
import com.touchgraph.graphlayout.NodeFilter;
import com.touchgraph.graphlayout.TGAbstractLens;
import com.touchgraph.graphlayout.TGException;
import com.touchgraph.graphlayout.TGLensSet;
import com.touchgraph.graphlayout.TGPanel;
import com.touchgraph.graphlayout.TGPoint2D;
import com.touchgraph.graphlayout.graphelements.GraphEltSet;
import com.touchgraph.graphlayout.graphelements.TGForEachNode;
import com.touchgraph.graphlayout.interaction.DragNodeUI;
import com.touchgraph.graphlayout.interaction.HVScroll;
import com.touchgraph.graphlayout.interaction.LocalityScroll;
import com.touchgraph.graphlayout.interaction.TGUIManager;
import com.touchgraph.graphlayout.interaction.ZoomScroll;

//import abdn.taxon.property.ui.EntityPropertyPanel;
/**
 * @author skrivov
 * ESDOntoBrowser.java
 *
 */
public class ESDOntoBrowser {
  public KRPolicy krPolicy;
  public RTPolicy rtPolicy;
  public NotificationPolicy ntPolicy;
  public RenderPolicy renPolicy;
  public GUIPolicy guiPolicy;
  private TGPanel tgPanel;

  private TGLensSet tgLensSet;
  public TGUIManager tgUIManager;

  public DragNodeUI dragNodeUI; //= new DragNodeUI(tgPanel);
  public OBNodeHintUI obNodeHintUI; // = new OBNodeHintUI(this);

  public HVScroll hvScroll;
  public ZoomScroll zoomScroll;
  public LocalityScroll localityScroll;

  boolean controlsVisible = true;
  //protected Hashtable actGroups;

  public URL documentBase;

  public boolean notificationEnabled = false;

  public static boolean deleteOnLClick = false;

  public ESDOntoBrowser(TGPanel tgP) {
    //Internal?
    //completeEltSet = new GraphEltSet();
    tgPanel = tgP;
    //completeEltSet=tgPanel.getCompleteEltSet();
    //tgPanel.setGraphEltSet(completeEltSet);
    tgLensSet = new TGLensSet();
    //GUI to be removed
    hvScroll = new HVScroll(tgPanel, tgLensSet);
    zoomScroll = new ZoomScroll(tgPanel);
    localityScroll = new LocalityScroll(tgPanel);
    //rotateScroll = new RotateScroll(tgPanel);
    initialize();
    buildLens();
    tgPanel.setLensSet(tgLensSet);
    //setVisible(true);
    OBNode.setNodeBackDefaultColor(Color.decode("#A04000"));
  }

  public ESDOntoBrowser(
      RTPolicy rtPol, //OntoFrame
      GUIPolicy guiPol, //EditorGUI
      KRPolicy krPol, //KRPolicyOWL
      RenderPolicy renPol,
      NotificationPolicy ntPol ) {
    this(guiPol.getTgPanel());
    krPolicy = krPol;
    rtPolicy = rtPol;
    ntPolicy = ntPol;
    renPolicy = renPol;
    guiPolicy = guiPol;
    if (krPolicy != null) {
      krPolicy.setOBPointer(this);
    }
    if (ntPolicy != null) {
      ntPolicy.setOBPointer(this);

    }
    guiPolicy.setOBPointer(this);
    tgPanel = guiPolicy.getTgPanel();
    guiPolicy.initialize();
    //this.propertyPanel = propPanel;
    addUIs();
  }

  public Set getObjectNodes(int type) {
    Set objects = new HashSet();
    GraphEltSet eltSet = getTGPanel().getCompleteEltSet();
    Node n;
    for (Iterator i = eltSet.getNodes().iterator(); i.hasNext(); ) {
      n = (Node) i.next();
      if (n instanceof OBObjectNode &&
          ( (OBObjectNode) n).objectCategory == type ) {
        objects.add(n);
      }
    }
    return objects;
  }

  public Set getRelationNodes(int type) {
    Set objects = new HashSet();
    GraphEltSet eltSet = getTGPanel().getCompleteEltSet();
    Node n;
    for (Iterator i = eltSet.getNodes().iterator(); i.hasNext(); ) {
      n = (Node) i.next();
      if (n instanceof OBRelationNode
          && ( (OBRelationNode) n).relationSubCategory == type) {
        objects.add(n);
      }
    }

    return objects;
  }

  /*public void setPropertyPanel( EntityPropertyPanel propPanel ) {
    this.propertyPanel = propPanel;
  }*/

  //Change view functions
  public void viewABox() {
    LocalityUtils localityUtils = tgPanel.getLocalityUtils();
    guiPolicy.restoreAll();
    TGForEachNode fen = new TGForEachNode() {
      public void forEachNode(Node node) {
        if (node instanceof OBObjectNode) {
          if ( ( (OBObjectNode) node).isClass) {
            node.markedForRemoval = true;
            node.isHiden = true;
          }
        }
        else if (node instanceof OBRelationNode) {
          if (! ( ( (OBRelationNode) node).relationCategory
                 == OBRelationNode.IS_INSTANCE
                 || ( (OBRelationNode) node).relationCategory
                 == OBRelationNode.IS_ATTRIBUTE
                 || ( (OBRelationNode) node).relationCategory
                 == OBRelationNode.IS_OBJECT_OPERATOR)) {
            node.markedForRemoval = true;
            node.isHiden = true;
          }
        }

      }
    };

    tgPanel.getCompleteEltSet().forAllNodes(fen);

    TGForEachNode fen2 = new TGForEachNode() {
      public void forEachNode(Node node) {
        if (node instanceof OBObjectNode
            && ! ( (OBObjectNode) node).isClass) {
          Vector types = ( (OBObjectNode) node).findTypes();
          for (Iterator iter = types.iterator(); iter.hasNext(); ) {
            OBObjectNode objNode = (OBObjectNode) iter.next();
            objNode.markedForRemoval = false;
            objNode.isHiden = false;
          }

        }
      }
    };

    tgPanel.getCompleteEltSet().forAllNodes(fen2);

    localityUtils.removeMarkedNodes();
    tgPanel.fireResetEvent();
    tgPanel.resetDamper();

  }

  public void viewTBox() {
    LocalityUtils localityUtils = tgPanel.getLocalityUtils();
    guiPolicy.restoreAll();
    TGForEachNode fen = new TGForEachNode() {
      public void forEachNode(Node node) {
        if (node instanceof OBObjectNode) {
          if (! ( (OBObjectNode) node).isClass) {
            node.markedForRemoval = true;
            node.isHiden = true;
          }
        }
        else if (node instanceof OBRelationNode) {
          if ( ( (OBRelationNode) node).relationCategory
              == OBRelationNode.IS_INSTANCE
              || ( (OBRelationNode) node).relationCategory
              == OBRelationNode.IS_ATTRIBUTE
              || ( (OBRelationNode) node).relationCategory
              == OBRelationNode.IS_OBJECT_OPERATOR) {
            node.markedForRemoval = true;
            node.isHiden = true;
          }
        }

      }
    };
    tgPanel.getCompleteEltSet().forAllNodes(fen);
    localityUtils.removeMarkedNodes();
    tgPanel.fireResetEvent();
    tgPanel.resetDamper();
  }

  public void viewAll() {
    guiPolicy.restoreAll();
    tgPanel.fireResetEvent();
    tgPanel.resetDamper();
  }

  public ActionListener showMoreAction = new ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent e) {
      if (tgPanel.getSelect() != null) {
        localityScroll.showMore(2);
        tgPanel.fireResetEvent();
        tgPanel.repaintAfterMove();
      }
      else {
        noNodeSelected();
      }
    }
  };

  public ActionListener showLessAction = new ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent e) {
      if (tgPanel.getSelect() != null) {
        localityScroll.showLess(2);
        tgPanel.fireResetEvent();
        tgPanel.repaintAfterMove();
      }
      else {
        noNodeSelected();
      }
    }
  };

  private void noNodeSelected() {
    guiPolicy.showErrorMessage("Command requires that a node be selected");
  }

  public ActionListener toggleControlsAction = new ActionListener() {
    public void actionPerformed(ActionEvent e) {
      controlsVisible = !controlsVisible;
      guiPolicy.setControlVisibility(controlsVisible);
    }
  };

  //Main API Functions

  public OBObjectNode createNewObject(float x, float y, int type) throws
      TGException {
    OBObjectNode n = new OBObjectNode();
    renPolicy.initObject(n, type);
    tgPanel.addNode(n, x, y);
   /* if (guiPolicy instanceof GUIPolicyEditor) {
      ( (GUIPolicyEditor) guiPolicy).addNotification(n);
    }*/
    //tgPanel.repaint();
    //setSelect(n);
    if (ntPolicy != null && notificationEnabled) {
      ntPolicy.creatNewObject(n.getID(), type);

    }
    return n;
  }

  public OBRelationNode createNewRelation(float x, float y, int type) throws
      TGException {
    OBRelationNode rn = new OBRelationNode();

    tgPanel.addNode(rn, x, y);
    renPolicy.initRelation(rn, type);
    rn.resetCategory(renPolicy);
    /*if (guiPolicy instanceof GUIPolicyEditor) {
      ( (GUIPolicyEditor) guiPolicy).addNotification(rn);
    }*/
    //tgPanel.repaint();
    //setSelect(rn);
    if (ntPolicy != null && notificationEnabled) {
      ntPolicy.createNewRelation(rn.getID(), type);
    }
    return rn;
  }

  public OBRelationNode createNewRelation(
      OBNode fromObj,
      OBNode toObj,
      int type) {
    if (toObj == null || type == 0) {
      return null;
    }
    if (!fromObj.isEditable()) {
      // cannot say something new about imported items
      return null;
    }
    OBRelationNode attrnode = new OBRelationNode();
    try {
      tgPanel.addNode(attrnode, fromObj.drawx, fromObj.drawy);
      //  (fromObj.drawx + toObj.drawx)/2, (fromObj.drawy + toObj.drawy)/2);
      tgPanel.addEdge(
          new OBEdge( (OBNode) fromObj, attrnode, OBEdge.START_EDGE));
      tgPanel.addEdge(
          new OBEdge(attrnode, (OBNode) toObj, OBEdge.END_EDGE));
      attrnode.drawx = (fromObj.drawx + toObj.drawx) / 2;
      attrnode.drawy = (fromObj.drawy + toObj.drawy) / 2;
      tgPanel.updatePosFromDraw(attrnode);
      renPolicy.initRelation(attrnode, type);
      attrnode.resetCategory(renPolicy);
      /*if (guiPolicy instanceof GUIPolicyEditor) {
        ( (GUIPolicyEditor) guiPolicy).addNotification(attrnode);
      }*/
      //tgPanel.repaint();
      //setSelect(attrnode);
      if (ntPolicy != null && notificationEnabled) {
        ntPolicy.createNewRelation(
            attrnode.getID(),
            type,
            fromObj.getID(),
            toObj.getID());
      }
    }
    catch (TGException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    return attrnode;
  }

  public OBEdge createNewEdge(OBNode fromObj, OBNode toObj, int order) {
    OBEdge ed = new OBEdge(fromObj, toObj, order);
    renPolicy.resetEdge(ed);
    tgPanel.addEdge(ed);
    if (guiPolicy instanceof GUIPolicyEditor) {
      ( (GUIPolicyEditor) guiPolicy).addEdgeNotification(ed);
    }

    if (ntPolicy != null && notificationEnabled) {
      ntPolicy.addLink(fromObj.getID(), toObj.getID());
    }
    return ed;
  }

  public void deleteNode(OBNode n, boolean notify) {
    if (n.isEditable() || n.getNamespace().equals("xsd")) {
      Node sel = tgPanel.getSelect();
      if (sel != null && sel.equals(n)) {
        clearSelect();
      }

      tgPanel.deleteNode(n);

      tgPanel.repaint();
      tgPanel.repaintAfterMove();
      /*  if (n instanceof OBObjectNode)
        deleteObject((OBObjectNode) n);
       else if (n instanceof OBRelationNode)
        deleteRelation((OBRelationNode) n);
       else
        return;*/

      /*if (guiPolicy instanceof GUIPolicyEditor && notify) {
        ( (GUIPolicyEditor) guiPolicy).deleteNotification(n);
      }*/

    }
  }

  /*
   public void deleteRelation(OBRelationNode rel) {
    //ClusterNode cn = rel.getParentCluster();
    //rel.freeEdgesFromClusters();
    //if (cn != null)
    //	cn.removeNodeFromCluster(rel);
    //rel.deleteDependentNodes(tgPanel);
    tgPanel.deleteNode(rel);
    tgPanel.repaint();
    tgPanel.repaintAfterMove();
   }
   public void deleteObject(OBObjectNode obj) {
    //	ClusterNode cn = obj.getParentCluster();
    //obj.freeEdgesFromClusters();
    //		 ((OBObjectNode) obj).deleteDependentNodes(tgPanel);
    //if (cn != null)
    //	cn.removeNodeFromCluster(obj);
    tgPanel.deleteNode(obj);
    tgPanel.repaint();
    tgPanel.repaintAfterMove();
   }*/

  public void deleteEdge(OBEdge e) {
    tgPanel.deleteEdge(e);
    if (guiPolicy instanceof GUIPolicyEditor) {
      ( (GUIPolicyEditor) guiPolicy).deleteEdgeNotification(e);
    }
    tgPanel.repaint();
    tgPanel.repaintAfterMove();
  }

  /*
    public OBRelationNode createNewRelation(OBNode fromObj, OBNode toObj)
   throws TGException {
   OBRelationNode attrnode = guiPolicy.createNewRelation(fromObj, toObj);
   if(attrnode==null) return null;
   tgPanel.setSelect(attrnode);
   //guiPolicy.setRelationNode((OBRelationNode) attrnode); goes to guiPolicy
   //		this is how notification can work
   if (ntPolicy != null &&notificationEnabled)
    ntPolicy.createNewRelation(
     attrnode.getID(),
     attrnode.relationSubCategory,
     fromObj.getID(),
     toObj.getID());
   return attrnode;
    }
    public void addObjectToRange(OBRelationNode rel, OBNode obj) {
   guiPolicy.addObjectToRange(rel, obj);
   if (ntPolicy != null&&notificationEnabled)
    ntPolicy.addObjectToRange(rel.getID(), obj.getID());
    }
    public void addObjectToDomain(OBRelationNode rel, OBNode obj) {
   guiPolicy.addObjectToDomain(rel, obj);
   if (ntPolicy != null&&notificationEnabled)
    ntPolicy.addObjectToDomain(rel.getID(), obj.getID());
    }
    public OBObjectNode createNewObject(float x, float y) throws TGException {
   OBObjectNode n = guiPolicy.createNewObject(  x,   y);
   if ( ntPolicy != null&&notificationEnabled)
     ntPolicy.creatNewObject(n.getID(), n.objectCategory);
   return n;
    }
    //the next 4 can be deleted as well
    public OBRelationNode createNewRelation(float x, float y)
   throws TGException {
   OBRelationNode rn = guiPolicy.createNewRelation(x,y);
   if ( ntPolicy != null&&notificationEnabled)
       ntPolicy.createNewRelation(rn.getID(), rn.relationSubCategory);
   return rn;
    }
    public void deleteRelation(OBRelationNode rel) {
   ClusterNode cn = rel.getParentCluster();
   rel.freeEdgesFromClusters();
   if (cn != null)
    cn.removeNodeFromCluster(rel);
   tgPanel.deleteNode(rel);
    }
    public void deleteObject(OBObjectNode obj) {
   ClusterNode cn = obj.getParentCluster();
   obj.freeEdgesFromClusters();
   ((OBObjectNode) obj).deleteDependentNodes(tgPanel);
   if (cn != null)
    cn.removeNodeFromCluster(obj);
   tgPanel.deleteNode(obj);
    }
   */

  public void expand(Node node, NodeFilter filter) {
    Node newNode;
    HashSet nodes = new HashSet();
    for (int i = 0;
         i < node.edgeNum();
         i++) { // get all attached visible nodes
      newNode = node.edgeAt(i).getOtherEndpt(node);
      if (newNode.isVisible()
          && (filter != null && filter.match(newNode))) {
        nodes.add(newNode);
      }
    }
    tgPanel.expandNode(node, filter);
    for (int i = 0; i < node.edgeNum(); i++) { // expand new relation nodes
      newNode = node.edgeAt(i).getOtherEndpt(node);
      if (!nodes.contains(newNode)
          && newNode instanceof OBRelationNode) {
        tgPanel.expandNode(newNode, null);
      }
    }

  }

  public URL getDocumentBase() {
    return documentBase;
  }

  public TGPanel getTGPanel() {
    return tgPanel;
  }

  public void setLocale(String nodeName, int radius) {
    OBNode n = (OBNode) tgPanel.getCompleteEltSet().findNode(nodeName);
    if (n != null) {
      tgPanel.setLocale(n, radius);
    }
    this.setSelect(n);
  }

  public OBNode getNodeByName(String nodeName) {
    Vector nodes =
        (Vector) tgPanel.getCompleteEltSet().findNodesByLabel(nodeName);
    if (nodes != null) {
      return (OBNode) nodes.firstElement();
    }
    return null;
  }

  public void setLocaleByName(String nodeName, int radius) {
    OBNode n = getNodeByName(nodeName);
    if (n != null) {
      tgPanel.setLocale(n, radius);
      this.setSelect(n);
      hvScroll.scrollToNode(n);
    }
  }

  public void setSelect(OBNode node) {
    tgPanel.setSelect(node);
    /*if (node instanceof OBRelationNode) {
      guiPolicy.setRelationNode( (OBRelationNode) node);
      //System.out.println("Is it here? " + node.getName() );
    }*/
    if (node instanceof OBObjectNode) {
      guiPolicy.setObjectNode( (OBObjectNode) node);
    }
  }

  public void clearSelect() {
    tgPanel.clearSelect();
    guiPolicy.setObjectNode(null);
  }

  class HorizontalStretchLens
      extends TGAbstractLens {
    protected void applyLens(TGPoint2D p) {
      p.x = p.x * 1.5;
    }

    protected void undoLens(TGPoint2D p) {
      p.x = p.x / 1.5;
    }
  }

  //Internal, but separate lenses from Scroll bars
  private void buildLens() {
    tgLensSet.addLens(hvScroll.getLens());
    tgLensSet.addLens(zoomScroll.getLens());
    //tgLensSet.addLens(rotateScroll.getLens());
    tgLensSet.addLens(new HorizontalStretchLens());
    tgLensSet.addLens(tgPanel.getAdjustOriginLens());
  }

  private void addUIs() {
    tgUIManager = new TGUIManager();
    OBEditUI editUI = new OBEditUI(this);

    OBNavigateUI navigateUI = new OBNavigateUI(this);
    OBDragAddClusterUI clusterUI = new OBDragAddClusterUI(this);

    tgUIManager.addUI(editUI, "Edit");
    tgUIManager.addUI(navigateUI, "Navigate");
    tgUIManager.addUI(clusterUI, "Cluster");
    //tgUIManager.addUI(dragNodeUI, "DragNode");
    obNodeHintUI = navigateUI.obNodeHintUI;
    dragNodeUI = navigateUI.dragNodeUI;
    //tgUIManager.addUI(obNodeHintUI, "NodeHint");
    tgUIManager.activate("Navigate");
  }

  /** A thread executed after reading from an XML file, that
   * sets the visibleLocale to the nodes makred as visible.
   */
  public class RestoreExactGraph
      extends Thread {
    public void run() {
      try {
        tgPanel.updateLocalityFromVisibility();
      }
      catch (TGException ex) {
        ex.printStackTrace();
      }

      clearSelect();
      tgPanel.fireResetEvent();
      // restoreSavedParameters(xmlio.getParameterHash());
    }
  }

  public void restoreSavedParameters(Hashtable params) {
    TGPoint2D offset = new TGPoint2D(0, 0);
    String x_str = (String) params.get("offsetX");
    String y_str = (String) params.get("offsetY");
    if (x_str != null && y_str != null) {
      offset.setX(Integer.parseInt(x_str));
      offset.setY(Integer.parseInt(y_str));
      hvScroll.setOffset(offset);
    }
    String zoom_str = (String) params.get("zoomSB");
    if (zoom_str != null) {
      //zoomScroll.getZoomSB().setValue(Integer.parseInt(zoom_str));
    }
    String rotate_str = (String) params.get("rotateSB");
    //if (rotate_str != null) {
    //	rotateScroll.getRotateSB().setValue(Integer.parseInt(rotate_str));
    //}
  }

  public void processHintURL(URL url) { /*
     if (enclosingApplet!=null) {
       AppletContext appletcontext = enclosingApplet.getAppletContext();
       appletcontext.showDocument(url, externalFrame);
      }
      else if (enclosingFrame!=null) {
       try { BrowserLauncher.openURL(url.toString()); }
       catch (Exception e) { e.printStackTrace(); }
      } */
   }

  private void initialize() {
    final JScrollBar horizontalSB = hvScroll.getHorizontalSB();
    final JScrollBar verticalSB = hvScroll.getVerticalSB();
    //final JScrollBar zoomSB = zoomScroll.getZoomSB();
    //final JScrollBar rotateSB = rotateScroll.getRotateSB();
    //final JScrollBar localitySB = localityScroll.getLocalitySB();

    //JPanel scrollPanel = new JPanel();
    //scrollPanel.setLayout(new GridBagLayout());
    //GridBagConstraints c = new GridBagConstraints();
    /*AbstractAction navigateAction = new AbstractAction("Navigate") {
      public void actionPerformed(ActionEvent e) {
        tgUIManager.activate("Navigate");
      }
    };
    AbstractAction editAction = new AbstractAction("Edit") {
      public void actionPerformed(ActionEvent e) {
        tgUIManager.activate("Edit");
      }
    };*/
    //obPopup = new JPopupMenu();

  }
}

